package com.data.center.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.data.center.dictionary.*;
import com.data.center.dto.OrganizationDto;
import com.data.center.dto.PersonDto;
import com.data.center.dto.StaffDto;
import com.data.center.entity.AdminDivision;
import com.data.center.entity.Dictionary.SpecializedTechnicalJob;
import com.data.center.entity.Person;
import com.data.center.entity.Staff;
import com.data.center.exception.exception.BizException;
import com.data.center.exception.info.CommonEnum;
import com.data.center.mapper.OrganizationMapper;
import com.data.center.mapper.PersonMapper;
import com.data.center.mapper.SpecializedTechnicalJobMapper;
import com.data.center.service.AdminDivisionService;
import com.data.center.service.OrganizationService;
import com.data.center.service.PersonService;
import com.data.center.util.AdminDivisionUtils;
import com.data.center.util.FieldDataManagementUtils;
import com.data.center.util.ForeignManage.ForeignDataItem;
import com.data.center.util.ForeignManage.ForeignDataUtil;
import com.data.center.util.ForeignManage.ForeignManageUtils;
import com.data.center.util.SnowflakeIdWorker;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
@Slf4j
public class PersonServiceImpl implements PersonService {

    @Resource
    private PersonMapper personMapper;
    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;
    @Autowired
    private AdminDivisionService adminDivisionService;
    @Autowired
    private OrganizationService organizationService;
    @Resource
    private OrganizationMapper organizationMapper;
    @Resource
    private SpecializedTechnicalJobMapper specializedTechnicalJobMapper;
    @Autowired
    private ForeignManageUtils foreignManageUtils;
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private ForeignDataUtil foreignDataUtil;
    private static final String DELETE = "DELETE";
    private static final String COVER_MODE = "COVER_MODE";

    private Map<String, String> K; // 用于检查P-M2原则的键名称MAP，同时储存该键在实体和数据库中的名称
    private Snowflake snowflake = new Snowflake();


    /**
     * @descripition: 构造函数，用于初始化集合K
     * **/
    public PersonServiceImpl() {
        K = new HashMap<>(); // 输入参数中key-数据查询键名称MAP
        K.put("nationalId", "national_id");
        K.put("mobile", "mobile");
    }

    @Override
    public Person getPersonById(String personId) {
        return personMapper.getPersonById(personId);
    }

    @Override
    public List<Person> getAllPersons() {
        return personMapper.getAllPersons();
    }


    /**
     * @Description:检查ID是否以P开头
     * */
    public boolean personIdVerify(PersonDto person) {
        return person.getPersonId().indexOf("P") == 0;
    }

    /**
     * @Description:规范化ID
     * */
    public boolean personIdStandardize(PersonDto person) {
        if (StringUtil.isEmpty(person.getPersonId())) {
            personIdSetDefault(person); // 生成ID
        } else {
            String result = "P" + person.getPersonId();
            if (result.length() >= 32) {
                person.setPersonId(result.substring(0, 32));// ID长度最多32，裁剪
            }
        }
        return true;
    }

    /**
     * @Description:设置默认ID
     * */
    public void personIdSetDefault(PersonDto person) {
        String result = "P" + snowflake.nextIdStr();
        person.setPersonId(result);
    }

    /**
     * @Description:检查姓名是否为空/符合要求
     * @没有对应的标准化方法，无法验证的数据就要抛出异常
     * */
    public boolean nameVerify(PersonDto person) {
        if (StringUtil.isEmpty(person.getName())) {
            throw new BizException("科技人才姓名不允许为空");
        }

        // 中文格式
        Pattern pattern = Pattern.compile("^[\u4e00-\u9fa5·]+$");
        Matcher matcher = pattern.matcher(person.getName());
        if (!matcher.matches()) {
            return true;
        }
        // 西文格式
        pattern = Pattern.compile("^[A-Za-z\\-' ]+$");
        matcher = pattern.matcher(person.getName());
        if (!matcher.matches()) {
            return true;
        }
        throw new BizException("科技人才姓名为不允许的格式");
    }

    /**
     * @Description:检查证件类型是否为要求类型
     * @没有对应的标准化方法，无法验证的数据就要抛出异常
     * */
    public boolean nationalIdTypeVerify(PersonDto person) {
        try {
            NationalIdType.valueOf(person.getNationalIdType());
        } catch (Exception e) {
            throw new BizException("证件类型非枚举类型");
        }
        return true;
    }


    /**
     * @Description:检查性別是否符合编码集:《中国科学技术协会数据标准》第1册：人才数据标准（试行）
     * */
    public boolean genderGroupVerify(PersonDto person) {
        try {
            Gender.getValueByKey(person.getGender());
        } catch (BizException e) {
            return false;
        }
        return true;
    }

    /**
     * @Description:标准化性別至编码集:《中国科学技术协会数据标准》第1册：人才数据标准（试行）
     * */
    public boolean genderStandardize(PersonDto person) {

        try {
            Gender.getValueByKey(person.getGender());
        } catch (BizException e) {
            try {
                Gender.getKeyByValue(person.getGender());
            } catch (BizException be) {
                throw new BizException("性別非枚举类型");
            }
        }
        return true;
    }

    /**
     * @Description:检查民族是否符合编码集:《中国科学技术协会数据标准》第1册：人才数据标准（试行）
     * */
    public boolean ethnicGroupVerify(PersonDto person) {
        try {
            Ethnicity.getValueByKey(person.getEthnicGroup());
        } catch (BizException e) {
            return false;
        }
        return true;
    }

    /**
     * @Description:标准化民族至编码集:《中国科学技术协会数据标准》第1册：人才数据标准（试行）
     * */
    public boolean ethnicGroupStandardize(PersonDto person) {

        try {
            Ethnicity.getValueByKey(person.getEthnicGroup());
        } catch (BizException e) {
            try {
                Ethnicity.getKeyByValue(person.getEthnicGroup());
            } catch (BizException be) {
                throw new BizException("民族非枚举类型");
            }
        }
        return true;
    }

    /**
     * @Description:判断国家编码是否符合入库标准
     * */
    public boolean nationalityVerify(PersonDto person) {
        try {
            CountryCode.getObjectByThreeCharCode(person.getNationality());
        } catch (BizException e) {
            return false;
        }
        return true;
    }

    /**
     * @Description:将国家名称、三位编码、数字编码转为对应的三位编码
     * */
    public String nationalityStandardize(PersonDto person) {
        try {
            return CountryCode.getObjectByThreeCharCode(person.getNationality()).getThreeCharCode();
        } catch (BizException e) {
            try {
                return CountryCode.getObjectByNumberCode(person.getNationality()).getThreeCharCode();
            } catch (BizException bizException) {
                try {
                    return CountryCode.getObjectByChineseName(person.getNationality()).getThreeCharCode();
                } catch (BizException nameBizException) {
                    throw new BizException(CommonEnum.COUNTRY_NOT_EXIST);
                }
            }
        }
    }

    /**
     * @Description:检查籍贯编码是否为8位，是否在库中存在
     * */
    public boolean birthplaceVerify(PersonDto person) {
        if (!AdminDivisionUtils.checkCodeLengthIsEight(person.getBirthplace())) {
            return false;
        }
        return adminDivisionService.getByCode(person.getBirthplace()) != null;
    }

    /**
     * @Description:标准化区域编码，对6位编码进行父编码查询拼接成8位编码，并检查是否在库中存在
     * */
    public void birthplaceStandardize(PersonDto person) {

        // 可能传入的是区域名称，尝试进行名称查询解码
        try {
            List<AdminDivision> adminDivisions = adminDivisionService.searchByName(person.getBirthplace());
            if (adminDivisions == null || adminDivisions.size() == 0 || adminDivisions.size() > 1) {
                throw new BizException("无法自动转换出生地");
            }
            person.setBirthplace(adminDivisions.get(0).getCode());
        } catch (MyBatisSystemException e) {
            throw new BizException(CommonEnum.ADMIN_DIVISION_NAME_CANT_GET);
        }

        // 检查编码是否为可解析或查询的位数，并自动解析6位编码
        if (AdminDivisionUtils.checkCodeLengthIsEight(person.getBirthplace())) {

        } else if (AdminDivisionUtils.checkCodeLengthIsSix(person.getBirthplace())) {
            // 传入的是6位，尝试直接解码
            person.setBirthplace(AdminDivisionUtils.getFatherCode(person.getBirthplace()).substring(0, 2) + person.getBirthplace());
        }

        // 查询编码是否在库中存在
        if (adminDivisionService.getByCode(person.getBirthplace()) == null) {
            throw new BizException(CommonEnum.DIVISION_CODE_WRONG);
        }
    }

    /**
     * @Description:检查政治面貌是否为字典中编码
     * */
    public boolean politicalAffiliationVerify(PersonDto person) {
        try {
            PoliticalAffiliation.getValueByKey(person.getPoliticalAffiliation());
        } catch (BizException e) {
            return false;
        }
        return true;
    }

    /**
     * @Description:标准化政治面貌，自动将文字转为编码
     * */
    public void politicalAffiliationStandardize(PersonDto person) {
        String code;
        try {
            code = PoliticalAffiliation.getValueByKey(person.getPoliticalAffiliation()).getKey();
        } catch (BizException e) {
            try {
                code = PoliticalAffiliation.getKeyByValue(person.getPoliticalAffiliation()).getKey();
            } catch (BizException bizException) {
                throw new BizException(CommonEnum.POLITICAL_AFFILIATION_NOT_EXIST);
            }
        }
        person.setPoliticalAffiliation(code);
    }

    /**
     * @Description:检查工作单位是否为已存在外键
     * */
    public boolean affiliationVerify(PersonDto person) {
        if (organizationMapper.selectById(person.getAffiliation()) == null) {
            return false;
        }
        return true;
    }

    /**
     * @Description:标准化工作单位，将单位名称通过自动查询标准化为外键
     * */
    public void affiliationStandardize(PersonDto person) {
        List<OrganizationDto> findOrg = organizationService.findOrganization(person.getAffiliation(), null);
        if (findOrg != null) {
            if (findOrg.size() != 1) {
                throw new BizException("工作单位无法自动标注化，请先入库工作单位组织");
            }
            person.setAffiliation(findOrg.get(0).getOrganizationId());
        } else {
            throw new BizException("工作单位无法自动标注化，请先入库工作单位组织");
        }
    }


    /**
     * @Description:检查行政级别是否为字典中的键值
     * */
    public boolean positionRankVerify(PersonDto person) {
        try {
            JobLevel.getValueByKey(person.getPositionRank());
        } catch (BizException e) {
            return false;
        }
        return true;
    }

    /**
     * @Description:标准化行政级别，自动将文字转为编码
     * */
    public void positionRankStandardize(PersonDto person) {
        String code;
        try {
            code = JobLevel.getValueByKey(person.getPositionRank()).getKey();
        } catch (BizException e) {
            try {
                code = JobLevel.getKeyByValue(person.getPositionRank()).getKey();
            } catch (BizException bizException) {
                throw new BizException(CommonEnum.RANK_NOT_EXIST);
            }
        }
        person.setPositionRank(code);
    }


    /**
     * @Description:检查专业技术职务是否为字典中的键值
     * */
    public boolean titleVerify(PersonDto person) {
        if (specializedTechnicalJobMapper.getByCode(person.getTitle()) == null) {
            return false;
        }
        return true;
    }

    /**
     * @Description:标准化专业技术职务，自动将文字转为编码
     * */
    public void titleStandardize(PersonDto person) {
        SpecializedTechnicalJob specializedTechnicalJob = specializedTechnicalJobMapper.getByCode(person.getTitle());
        if (specializedTechnicalJob == null) {
            try {
                specializedTechnicalJob = specializedTechnicalJobMapper.searchByName(person.getTitle()).get(0);
            } catch (BizException bizException) {
                throw new BizException(CommonEnum.TITLE_NOT_EXIST);
            } catch (NullPointerException nullPointerException) {
                throw new BizException(CommonEnum.TITLE_NOT_EXIST);
            }
        }
        if (specializedTechnicalJob == null) {
            throw new BizException(CommonEnum.TITLE_NOT_EXIST);
        }
        person.setTitle(specializedTechnicalJob.getCode());
    }

    /**
     * @Description:检查毕业院校是否为已存在外键
     * */
    public boolean graduationVerify(PersonDto person) {
        if (organizationMapper.findById(person.getGraduation()) == null) {
            return false;
        }
        return true;
    }

    /**
     * @Description:标准化毕业院校，将毕业院校名称通过自动查询标准化为外键
     * */
    public void graduationStandardize(PersonDto person) {
        List<OrganizationDto> findOrg = organizationService.findOrganization(person.getGraduation(), null);
        if (findOrg != null) {
            if (findOrg.size() != 1) {
                throw new BizException("毕业院校无法自动标注化，请先入库毕业院校组织");
            }
            if (!findOrg.get(0).getCategory().equals(OrganizationCategory.UNIVERSITY.getKey())) {
                throw new BizException("毕业院校无法自动标注化，类型非高校");
            }
            person.setGraduation(findOrg.get(0).getOrganizationId());
        } else {
            throw new BizException("毕业院校无法自动标注化，请先入库毕业院校组织");
        }
    }

    /**
     * @Description:检查所学专业是否为字典中Key
     * */
    public boolean majorVerify(PersonDto person) {
        try {
            MajorStudied.getValueByKey(person.getMajor());
        } catch (BizException e) {
            return false;
        }
        return true;
    }

    /**
     * @Description:标准化所学专业，自动将文字转为编码
     * */
    public void majorStandardize(PersonDto person) {
        String code;
        try {
            code = MajorStudied.getValueByKey(person.getMajor()).getKey();
        } catch (BizException e) {
            try {
                code = MajorStudied.getKeyByValue(person.getMajor()).getKey();
            } catch (BizException bizException) {
                throw new BizException(CommonEnum.MAJOR_NOT_EXIST);
            }
        }
        person.setMajor(code);
    }

    /**
     * @Description:检查最高学历是否为字典中Key
     * */
    public boolean educationVerify(PersonDto person) {
        try {
            EducationLevel.getValueByKey(person.getEducation());
        } catch (BizException e) {
            return false;
        }
        return true;
    }
    /**
     * @Description:标准化最高学历，自动将文字转为编码
     * */
    public void educationStandardize(PersonDto person) {
        String code;
        try {
            code = EducationLevel.getValueByKey(person.getEducation()).getKey();
        } catch (BizException e) {
            try {
                code = EducationLevel.getKeyByValue(person.getEducation()).getKey();
            } catch (BizException bizException) {
                throw new BizException(CommonEnum.EDUCATION_NOT_EXIST);
            }
        }
        person.setEducation(code);
    }

    /**
     * @Description:检查最高学位是否为字典中Key
     * */
    public boolean degreeVerify(PersonDto person) {
        try {
            AcademicDegree.getValueByKey(person.getDegree());
        } catch (BizException e) {
            return false;
        }
        return true;
    }
    /**
     * @Description:标准化最高学位，自动将文字转为编码
     * */
    public void degreeStandardize(PersonDto person) {
        String code;
        try {
            code = AcademicDegree.getValueByKey(person.getDegree()).getKey();
        } catch (BizException e) {
            try {
                code = AcademicDegree.getKeyByValue(person.getDegree()).getKey();
            } catch (BizException bizException) {
                throw new BizException(CommonEnum.DEGREE_NOT_EXIST);
            }
        }
        person.setDegree(code);
    }


    /**
     * @Description:检查学科是否为字典中Key
     * */
    public boolean disciplinesVerify(PersonDto person) {
        try {
            AcademicDiscipline.getValueByKey(person.getDisciplines());
        } catch (BizException e) {
            return false;
        }
        return true;
    }
    /**
     * @Description:标准化学科，自动将文字转为编码
     * */
    public void disciplinesStandardize(PersonDto person) {
        String code;
        try {
            code = AcademicDiscipline.getValueByKey(person.getDisciplines()).getKey();
        } catch (BizException e) {
            try {
                code = AcademicDiscipline.getKeyByValue(person.getDisciplines()).getKey();
            } catch (BizException bizException) {
                throw new BizException(CommonEnum.DISCIPLINES_NOT_EXIST);
            }
        }
        person.setDisciplines(code);
    }

    /**
     * @Description:检查所在地编码是否为8位，是否在库中存在
     * */
    public boolean divisionVerify(PersonDto person) {
        if (!AdminDivisionUtils.checkCodeLengthIsEight(person.getDivision())) {
            return false;
        }
        return adminDivisionService.getByCode(person.getDivision()) != null;
    }
    /**
     * @Description:标准化所在地编码，对6位编码进行父编码查询拼接成8位编码，并检查是否在库中存在
     * */
    public void divisionStandardize(PersonDto person) {

        // 可能传入的是区域名称，尝试进行名称查询解码
        try {
            AdminDivision adminDivision = adminDivisionService.getByName(person.getDivision());
            if (adminDivision != null) {
                person.setDivision(adminDivision.getCode());
            }
        } catch (MyBatisSystemException e) {
            throw new BizException(CommonEnum.ADMIN_DIVISION_NAME_CANT_GET);
        }

        // 检查编码是否为可解析或查询的位数，并自动解析6位编码
        if (AdminDivisionUtils.checkCodeLengthIsEight(person.getDivision())) {

        } else if (AdminDivisionUtils.checkCodeLengthIsSix(person.getDivision())) {
            // 传入的是6位，尝试直接解码
            person.setDivision(AdminDivisionUtils.getFatherCode(person.getDivision()).substring(0, 2) + person.getDivision());
        }

        // 查询编码是否在库中存在
        if (adminDivisionService.getByCode(person.getDivision()) == null) {
            throw new BizException(CommonEnum.DIVISION_CODE_WRONG);
        }
    }


    /**
     * @Description:检查实名认证状态状态是否为字典中Key
     * */
    public boolean authenticationVerify(PersonDto person) {
        try {
            AuthenticationType.getValueByKey(person.getAuthentication());
        } catch (BizException e) {
            return false;
        }
        return true;
    }
    /**
     * @Description:标准化实名认证状态状态，自动将文字转为编码
     * */
    public void authenticationStandardize(PersonDto person) {
        String code;
        try {
            code = AuthenticationType.getValueByKey(person.getAuthentication()).getKey();
        } catch (BizException e) {
            try {
                code = AuthenticationType.getKeyByValue(person.getAuthentication()).getKey();
            } catch (BizException bizException) {
                throw new BizException(CommonEnum.AUTHENTICATION_NOT_EXIST);
            }
        }
        person.setAuthentication(code);
    }

    /**
     * @Description:检查个人状态是否为字典中Key
     * */
    public boolean statusVerify(PersonDto person) {
        try {
            Status.getValueByKey(person.getStatus());
        } catch (BizException e) {
            return false;
        }
        return true;
    }
    /**
     * @Description:标准化个人状态，自动将文字转为编码
     * */
    public void statusStandardize(PersonDto person) {
        String code;
        try {
            code = Status.getValueByKey(person.getStatus()).getKey();
        } catch (BizException e) {
            try {
                code = Status.getKeyByValue(person.getStatus()).getKey();
            } catch (BizException bizException) {
                throw new BizException(CommonEnum.STATUS_NOT_EXIST);
            }
        }
        person.setStatus(code);
    }

    /**
     * 标准化PersonDto对象
     * @param person PersonDto对象
     * @return 标准化后的PersonDto对象
     * @throws InvocationTargetException 抛出目标方法调用时发生的异常
     * @throws IllegalAccessException 抛出访问字段或方法发生错误时的异常
     */
    public PersonDto standardizePerson(PersonDto person) throws InvocationTargetException, IllegalAccessException {
        for (Field field: PersonDto.class.getDeclaredFields()) {
            // 排除不需要進行核驗的鍵
            if (!"dob".equals(field.getName()) && !"authentication".equals(field.getName()) && !"status".equals(field.getName()) && StringUtil.isNotEmpty((String) BeanUtil.getFieldValue(person, field.getName()))
            ) { // 只校验/标准化有数据的键
                if (!FieldDataManagementUtils.verify(
                        this,
                        PersonServiceImpl.class,
                        field.getName(),
                        person,
                        PersonDto.class)
                ) {
                    FieldDataManagementUtils.standardize(
                            this,
                            PersonServiceImpl.class,
                            field.getName(),
                            person,
                            PersonDto.class
                    ); // 检验不通过自动尝试标准化
                }
            }
        }
        return person;
    }

    @Override
    public List<PersonDto> findPerson(PersonDto person) {
        if (StringUtil.isEmpty(person.getName())) {
            throw new BizException("查询人才姓名不允许为空"); // P-M1
        }



        // 检查姓名是否规范
        nameVerify(person);
//        baseQueryParam.put("name", person.getName());

        // P-M2
//        Map<String, String> K = new HashMap<>(); // 输入参数中key-数据查询键名称MAP
//        K.put("nationalId", "national_id");
//        K.put("mobile", "mobile");
        Set<Person> cachePersonList = new HashSet<>();
        // 构造查询参数
        QueryWrapper<Person> param = new QueryWrapper<>();
        param.eq("name", person.getName());
        boolean hasOtherVerify = false;
        for (String key: K.keySet()) {
            if (StringUtil.isNotEmpty((String)BeanUtil.getFieldValue(person, key))) { // 输入参数中不为空，则进行与姓名的组合查询
                hasOtherVerify = true;
                param.eq(K.get(key), BeanUtil.getFieldValue(person, key));
//                baseQueryParam.put(K.get(key), BeanUtil.getFieldValue(person, key)); // 构造查询条件
//                cachePersonList.addAll(personMapper.selectByMap(baseQueryParam)); // 将该次查询的结果存入HashSet，通过ID去重
//                baseQueryParam.remove(K.get(key)); // 查询后将nationalId / mobile的条件删除
            }
        }
        cachePersonList.addAll(personMapper.selectList(param)); // 将查询的结果存入HashSet，通过ID去重
//        if (!hasOtherVerify) { // 如果没有任何K中判断，则退化为查询名称
//            cachePersonList.addAll(personMapper.selectList(param)); // 将查询的结果存入HashSet，通过ID去重
//        }
        // 至多查询得到2个人才
        if (cachePersonList.size() > 2) {
            throw new BizException("库中存在数据破坏了P-M3原则" + cachePersonList);
        }

        return BeanUtil.copyToList(cachePersonList, PersonDto.class); // 转换为Dto链表
    }

    @Override
    public PersonDto addPerson(PersonDto person){
        // P-M1
        nameVerify(person);

        // P-M2
        boolean isExist = false;
        for (String key: K.keySet()) {
            if (StringUtil.isNotEmpty((String)BeanUtil.getFieldValue(person, key))) { // 输入参数中不为空，则说明存在交集
                isExist = true;
            }
        }
        if (!isExist) {
            throw new BizException("违反科技人员P-M2原则");
        }

        // 标准化
        PersonDto standardizedPerson;
        try {
            standardizedPerson = standardizePerson(person);
        } catch (InvocationTargetException invocationTargetException) {
            throw new BizException("标准化PersonDto对象失败" + invocationTargetException.getTargetException());
        } catch(IllegalAccessException illegalAccessException) {
            throw new BizException("标准化PersonDto对象失败" + illegalAccessException);
        }

        // P-M3
        List<PersonDto> findPerson = findPerson(standardizedPerson);
        if (findPerson != null && findPerson.size() > 0) {
            throw new BizException("新增科技人员已存在，违反P-M3约束");
        }

        // P-M4
        // TODO:使用公安部核验接口对身份信息进行核验
        // Result result = authenticationService.authentication(standardizedPerson);
        // 现在随机判断是否通过，5%的概率不通过
//        Random random = new Random();
//        int checkResult = random.nextInt(100);
//        if (checkResult <= 5) {
//            throw new BizException(CommonEnum.AUTHENTICATION_PERSON_FAIL); // 此处应有对应的机制捕获该类型的异常，并对这部分科技人员数据进行缓存，并允许工作人员能够强行通过该类数据
//        }

        // 设置认证信息
        standardizedPerson.setAuthentication(AuthenticationType.PUBLIC_SECURITY_TWO_ELEMENT.getKey());
        standardizedPerson.setAuthenticator("NCIIC");
        standardizedPerson.setAuthenticateTime(new Date());

        personMapper.insertPerson(BeanUtil.copyProperties(person, Person.class));

        return BeanUtil.copyProperties(person, PersonDto.class);
    }

    @Override
    public PersonDto forceAddPerson(PersonDto person){
        // P-M1
        nameVerify(person);

        // P-M2
        boolean isExist = false;
        for (String key: K.keySet()) {
            if (StringUtil.isNotEmpty((String)BeanUtil.getFieldValue(person, key))) { // 输入参数中不为空，则说明存在交集
                isExist = true;
            }
        }
        if (!isExist) {
            throw new BizException("违反科技人员P-M2原则");
        }

        // 标准化
        PersonDto standardizedPerson;
        try {
            standardizedPerson = standardizePerson(person);
        } catch (InvocationTargetException invocationTargetException) {
            throw new BizException("标准化PersonDto对象失败" + invocationTargetException.getTargetException());
        } catch(IllegalAccessException illegalAccessException) {
            throw new BizException("标准化PersonDto对象失败" + illegalAccessException);
        }

        // P-M3
        List<PersonDto> findPerson = findPerson(standardizedPerson);
        if (findPerson != null && findPerson.size() > 0) {
            throw new BizException("新增科技人员已存在，违反P-M3约束");
        }

        standardizedPerson.setAuthentication(AuthenticationType.BUSINESS_TWO_ELEMENT.getKey());
        standardizedPerson.setAuthenticator("now_manager"); // TODO:接入人员管理系统后，需要修改
        standardizedPerson.setAuthenticateTime(new Date());

        personIdSetDefault(standardizedPerson);

        personMapper.insertPerson(BeanUtil.copyProperties(standardizedPerson, Person.class));
        return standardizedPerson;
    }


    @Override
    public PersonDto updatePerson(PersonDto originalPerson, PersonDto newPerson){

        // P-M1
        if (StringUtil.isEmpty(newPerson.getName())) {
//        if (newPerson.getKeyWithAdditionalInformation().contains("name") && StringUtil.isEmpty(newPerson.getName())) {
            throw new BizException("更新人才姓名不允许为空");
        }

        PersonDto standardizedPerson;
        try {
            standardizedPerson = standardizePerson(newPerson);
        } catch (InvocationTargetException invocationTargetException) {
            throw new BizException("标准化PersonDto对象失败" + invocationTargetException.getTargetException());
        } catch(IllegalAccessException illegalAccessException) {
            throw new BizException("标准化PersonDto对象失败" + illegalAccessException);
        }

        // 更新K+name信息指定更新键的对应值,用于后续判断S-M2与S-M3原则
        K.put("name", "name");
        PersonDto updateKValue = new PersonDto();
        for (String key: K.keySet()) { // 设置姓名 + 其余2要素
            if (BeanUtil.getFieldValue(standardizedPerson, key)!= null) {
                BeanUtil.setFieldValue(updateKValue, key, BeanUtil.getFieldValue(standardizedPerson, key));
            }
        }
        K.remove("name");

        // 判断是否不符合S-M2原则
        boolean unSafe = true;
        for (String key: K.keySet()) {
            if (StringUtil.isNotEmpty((String) BeanUtil.getFieldValue(updateKValue, key))) {
                unSafe = false;
            }
        }
        if (unSafe) {
            throw new BizException("业务人员信息不完整,违反S-M2");
        }
//        // 根据增量信息设置需要更新的字段
//        // 如果该字段有核验和标准化方法，则进行核验和标准化
//        log.info("自动校验标准化待更新字段结果：" + standardizedPerson);
//        standardizedPerson.getKeyWithAdditionalInformation().forEach(item -> {
//            switch (standardizedPerson.getAdditionalInformation().get(item)) {
//                case DELETE:
//                    setDefaultValues(standardizedPerson, item.toString());
//                    break;
//                default: // 默认采用更新
//                    BeanUtil.setFieldValue(originalPerson, item.toString(), BeanUtil.getFieldValue(standardizedPerson, item.toString()));
//                    break;
//            }
//        });
//
//        // P-M2
//        boolean allNull = true;
//        for (String key: K.keySet()) {
//            if (BeanUtil.getFieldValue(originalPerson, key) != null) {
//                allNull = false;
//            }
//        }
//        if (allNull) {
//            throw new BizException("更新科技人员信息会导致缺失认证信息");
//        }

        // P-M3
        List<PersonDto> findPerson = findPerson(updateKValue);
        Set<PersonDto> findResultSet = new HashSet<>();
        findResultSet.addAll(findPerson);
        findResultSet.remove(originalPerson);
        if (findResultSet.size() != 0) {
            throw new BizException("库中已经存在数据，更新将破坏S-M3原则"); // S-M3
        }
//        if (findPerson.size() > 1){
//            // 如果找到了多个，则说明更改后的身份证+手机号会破坏P-M3原则
//            throw new BizException("无法更新，破坏了S-M3原则");
//        } else if (findPerson.size() == 1) {
//            // 如果只找到了一个，需要确定是否找到的就是原本的科技人员
//            if (!findPerson.get(0).getPersonId().equals(originalPerson.getPersonId())) {
//                // 如果找到的不是原本的科技人才，那么说明这个更改会使用库里其他人才的手机/身份证号
//                throw new BizException("无法更新，此更新会破坏S-M3原则");
//            }
//            // 如果是原本的人才，那说明这个更新不破坏P-M3
//        }
        // 一个都没找到，说明这个更新不破坏P-M3

        // P-M4
        if (StringUtil.isNotEmpty(standardizedPerson.getAuthentication())) {
            if (StringUtil.isEmpty(standardizedPerson.getAuthentication()) || standardizedPerson.getAuthentication().equals("00")) {
                throw new BizException("更新的人才认证状态不允许为空");
            }
            if (!standardizedPerson.getAuthentication().equals(originalPerson.getAuthentication())) {
                if (authenticationVerify(standardizedPerson)) {
                    standardizedPerson.setAuthenticator("认证人");
                    standardizedPerson.setAuthenticateTime(new Date());
                } else {
                    throw new BizException("更新的人才认证状态不合法");
                }
            }
        }

        personMapper.updatePerson(BeanUtil.copyProperties(standardizedPerson, Person.class));

        return originalPerson;
    }

    /**
     * 逻辑删除
     * 假删除，将数据状态设置为离职
     * @Param id
     */
    @Override
    public boolean logicalDelete(String id) {
        Person staff = personMapper.selectById(id);
        staff.setStatus(Status.RETIRED.getKey()); // 默认设置成离退状态
        staff.setModifier("DefaultDeleter"); // TODO:设置实际修改者
        staff.setLastModifiedTime(new Date());
        personMapper.updateById(staff);
        return true;
    }

    /**
     * @description:物理删除
     * 物理删除，将数据从数据库中删除
     */
    @Override
    public boolean physicalDelete(String id) throws InvocationTargetException, IllegalAccessException {
        if (StringUtil.isEmpty(id) || personMapper.getPersonById(id) == null) {
            // 删除失败，抛出异常
            throw new BizException("被删除的ID不存在");
        }

        List<String> errorList = new ArrayList<>(); // 记录错误信息
        // 获取所有依赖本表的表
        Person person = personMapper.selectById(id);
        int count = 0;
        for (ForeignDataItem item : foreignManageUtils.getForeignDataItem(Person.class.getName())) {
            List list = (List) item.searchByForeignKeyMethod.invoke(
                    applicationContext.getBean((Class) item.serviceClass),
                    BeanUtil.getFieldValue(person, item.foreignKey)
            );
            errorList.addAll(list);
            count += list.size();
        }

        if (count > 0) {
            log.error("物理删除科技人员" + id + "失败，存在依赖：" + errorList);
            throw new BizException(CommonEnum.DELETE_FALSE);
        }

        personMapper.deleteById(id);
        return true;
    }

    /**
     * 合并员工信息
     * @param personDto 待合并的员工对象
     * @param deletedPerson 被删除的员工对象
     * @return 合并后的员工对象
     * @throws InvocationTargetException 当调用方法时抛出的异常
     * @throws IllegalAccessException 当访问类或方法时抛出的异常
     */
    @Override
    public PersonDto merge(PersonDto personDto, PersonDto deletedPerson) throws InvocationTargetException, IllegalAccessException {
        if (StringUtil.isEmpty(deletedPerson.getPersonId()) || personMapper.getPersonById(deletedPerson.getPersonId()) == null) {
            // 合并失败，抛出异常
            throw new BizException("被合并的员工不存在");
        }

        // 检查依赖
        foreignDataUtil.mergeByForeignKey(personDto, deletedPerson);

        // 依赖清理结束后，删除数据
        personMapper.deleteById(deletedPerson.getPersonId());
        return personDto;
    }

    /**
     * 设置字段默认值
     * @param personDto
     * @param propertyName
     */
    public void setDefaultValues(PersonDto personDto, String propertyName) {
        switch (propertyName) {
            case "birthplace":
                personDto.setBirthplace("00000000");
                break;
            case "division":
                personDto.setDivision("00000000");
                break;
            default:
                BeanUtil.setFieldValue(personDto, propertyName, null);
                break;
        }
    }

    @Override
    public void updatePerson(Person person) {
        personMapper.updatePerson(person);
    }

    @Override
    public void deletePerson(String personId) {
        personMapper.deletePerson(personId);
    }

    /**
     * @Description:工作单位外键依赖服务查询方法
     * */
    @Override
    public List<Person> searchByAffiliation(String id) {
        // 构造查询参数
        Map<String, Object> queryParams = new HashMap<>();
        queryParams.put("affiliation", id);
        return personMapper.selectByMap(queryParams);
    }
    /**
     * @Description:工作单位外键依赖服务删除方法
     * */
    @Override
    public int deleteByAffiliation(String id) {
        // 构造查询参数
        Map<String, Object> queryParams = new HashMap<>();
        queryParams.put("affiliation", id);
        personMapper.deleteByMap(queryParams);
        return 1;
    }
    /**
     * @description:Affiliation外键上的合并方法，将Affiliation为deletedId的数据的Affiliation修改为id
     * @param id
     * @param deletedId
     * @return
     */
    @Override
    public int mergeByAffiliation(String id, String deletedId) {
        log.info("mergeByForeignKey参数" + id + "  " + deletedId );
        Map<String, Object> queryParams = new HashMap<>();
        queryParams.put("affiliation", deletedId);
        List<Person> delededPersons = personMapper.selectByMap(queryParams);
        for (Person mergeItem : delededPersons) {
            mergeItem.setAffiliation(id);
            personMapper.updatePerson(mergeItem);
        }
        return 1;
    }

    /**
     * @Description:毕业院校外键依赖服务查询方法
     * */
    @Override
    public List<Person> searchByGraduation(String id) {
        // 构造查询参数
        Map<String, Object> queryParams = new HashMap<>();
        queryParams.put("graduation", id);
        return personMapper.selectByMap(queryParams);
    }
    /**
     * @Description:毕业院校外键依赖服务删除方法
     * */
    @Override
    public int deleteByGraduation(String id) {
        // 构造查询参数
        Map<String, Object> queryParams = new HashMap<>();
        queryParams.put("graduation", id);
        personMapper.deleteByMap(queryParams);
        return 1;
    }
    /**
     * @description:graduation外键上的合并方法，将graduation为deletedId的数据的graduation修改为id
     * @param id
     * @param deletedId
     * @return
     */
    @Override
    public int mergeByGraduation(String id, String deletedId) {
        log.info("mergeByForeignKey参数" + id + "  " + deletedId );
        Map<String, Object> queryParams = new HashMap<>();
        queryParams.put("graduation", deletedId);
        List<Person> deletedPersons = personMapper.selectByMap(queryParams);
        for (Person mergeItem : deletedPersons) {
            mergeItem.setGraduation(id);
            personMapper.updatePerson(mergeItem);
        }
        return 1;
    }
}
